home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1999 March
/
EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso
/
earcd
/
devel
/
vbcc-68k-src
/
vlink
/
main.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-01-01
|
13KB
|
451 lines
/* $VER: vlink main.c V0.6 (24.10.98)
*
* This file is part of vlink, a portable linker for multiple
* object formats.
* Copyright (c) 1997-99 Frank Wille
*
* vlink is freeware and part of the portable and retargetable ANSI C
* compiler vbcc, copyright (c) 1995-99 by Volker Barthelmann.
* vlink may be freely redistributed as long as no modifications are
* made and nothing is charged for it. Non-commercial usage is allowed
* without any restrictions.
* EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
* SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
*
*
* v0.6 (24.10.98) phx
* -baseoff will modify the base-reg section offset for the
* destination target.
* Deleted obsolete make_baserel_offsets().
* v0.5d (22.08.98) phx
* Faster memory allocation can be activated by #define FASTALLOC.
* v0.5 (27.06.98) phx
* -v shows default target.
* v0.4 (05.06.98) phx
* -sc forces merging of all code sections in an executable.
* -sd forces merging of all data and bss sections in an executable.
* -multibase prevents auto-merging of sections, which are accessed
* base-relative.
* Call linker_relrefs() to find all relative references between
* sections.
* v0.3 (16.04.98) phx
* -R directs vlink to generate short relocs, if the target format
* allows this. It is for example supported by ELF and AmigaDos.
* New option -F for reading a list of input files.
* v0.2 (07.03.98) phx
* -v shows standard library path.
* v0.1 (27.02.98) phx
* First version that seems to link AmigaOS ADOS and EHF
* objects and libraries. Many common features, like linking
* sections together which have relative references, are
* still missing. Also, PowerPC-ELF32 support is about to come.
* v0.0 (04.08.97) phx
* File created. Project started on a beautiful summer-day
* at the North Sea beach of Cuxhaven. :)
*/
#define MAIN_C
#include "vlink.h"
struct GlobalVars gvars;
void cleanup(struct GlobalVars *);
static char *get_option_arg(int,char *[],int *);
static void ReadListFile(struct GlobalVars *,char *);
main(int argc,char *argv[])
{
struct GlobalVars *gv = &gvars;
int i,j;
char *buf;
struct LibPath *libp;
struct InputFile *ifn;
bool stdlib;
bool dynamic = TRUE; /* link with dynamic libraries first */
int so_version = 0; /* minum version for shared objects */
#ifdef FASTALLOC
init_mem();
#endif
/* initialize and set default values */
memset(gv,0,sizeof(struct GlobalVars));
initlist(&gv->libpaths);
#ifdef LIBPATH
libp = alloc(sizeof(struct LibPath));
libp->path = LIBPATH; /* default search path */
addtail(&gv->libpaths,&libp->n);
stdlib = TRUE;
#else
stdlib = FALSE;
#endif
#ifdef DEFTARGET
for (j=0; fff[j]; j++) {
if (!strcmp(fff[j]->tname,DEFTARGET)) {
gv->dest_format = (uint8)j;
break;
}
}
if (fff[j] == NULL) {
fprintf(stderr,"Configuration warning: Selected default target "
"\"%s\" is not included.\nThe current default target "
"is \"%s\".\n",DEFTARGET,fff[gv->dest_format]->tname);
printf("\n");
}
#endif
initlist(&gv->inputlist);
initlist(&gv->lnksec);
gv->dest_name = "a.out";
gv->maxerrors = DEF_MAXERRORS;
if (argc<2 || (argc==2 && *argv[1]=='?')) {
show_usage();
exit(EXIT_SUCCESS);
}
for (i=1; i<argc; i++) {
if (*argv[i] == '-') { /* option detected */
switch (argv[i][1]) {
case 'b':
if (!strcmp(&argv[i][2],"aseoff")) { /* set base-relative offset */
++i;
if (i<argc && *argv[i]!='-') {
long bo;
sscanf(argv[i],"%li",&bo);
fff[gv->dest_format]->baseoff = bo;
}
else
error(34,argv[--i]); /* option requires argument */
}
else { /* select target format */
if (buf = get_option_arg(argc,argv,&i)) {
for (j=0; fff[j]; j++)
if (!strcmp(fff[j]->tname,buf))
break;
if (fff[j])
gv->dest_format = (uint8)j;
else
error(9,buf); /* invalid target format */
}
else
error(5,'b'); /* option requires argument */
}
break;
case 'd':
if (buf = get_option_arg(argc,argv,&i)) {
switch (*buf) {
case 'n': /* static */
dynamic = FALSE;
break;
case 'y': /* dynamic */
dynamic = TRUE;
break;
case 'c':
gv->alloc_common = TRUE; /* force alloc. of common syms. */
break;
case 'p':
/* @@@ something with procedures... don't know */
break;
default:
error(4,*buf); /* unknown argument for option -d */
break;
}
}
else
error(5,'d'); /* option requires argument */
break;
case 'h': /* help text */
show_usage();
exit(EXIT_SUCCESS);
case 'l': /* library specifier */
if (buf = get_option_arg(argc,argv,&i)) {
ifn = alloc(sizeof(struct InputFile));
ifn->name = buf;
ifn->lib = TRUE;
ifn->dynamic = dynamic;
ifn->so_ver = so_version;
so_version = 0;
addtail(&gv->inputlist,&ifn->n);
}
else
error(5,'l'); /* option requires argument */
break;
case 'm':
if (!strcmp(&argv[i][2],"ultibase"))
gv->multibase = TRUE;
else
error(2,argv[i]); /* unrecognized option */
break;
case 'n':
if (!strcmp(&argv[i][2],"ostdlib")) {
if (stdlib) {
remhead(&gv->libpaths);
stdlib = FALSE;
}
}
else
error(2,argv[i]); /* unrecognized option */
break;
case 'o': /* set output file name */
if (!(gv->dest_name = get_option_arg(argc,argv,&i)))
error(5,'o'); /* option requires argument */
break;
case 'r': /* output is an relocatable object again */
gv->dest_object = TRUE;
break;
case 's':
switch (argv[i][2]) {
case '\0': /* strip all symbols */
gv->strip_symbols = STRIP_ALL;
break;
case 'c': /* -sc force small code */
gv->small_code = TRUE;
break;
case 'd': /* -d force small data */
gv->small_code = TRUE;
break;
case 't': /* -static */
dynamic = FALSE;
break;
default:
error(2,argv[i]); /* unrecognized option */
break;
}
break;
case 't': /* trace file accesses */
gv->trace_file = stderr;
break;
case 'u': /* mark symbol as undefined */
/* @@@ ... */
break;
case 'v': /* show version and target info */
show_version();
printf("Standard library path: %s\nDefault target: %s\n"
"Supported targets:", stdlib ?
((struct LibPath *)(gv->libpaths.first))->path : "none",
fff[gv->dest_format]->tname);
for (j=0; fff[j]; j++)
printf(" %s",fff[j]->tname);
printf("\n");
exit(EXIT_SUCCESS);
case 'w': /* suppress warnings */
gv->dontwarn = TRUE;
break;
case 'x': /* discard all local symbols */
gv->discard_local = DISLOC_ALL;
break;
case 'y': /* trace all accesses on a specific symbol */
if (gv->trace_syms == NULL)
gv->trace_syms = alloc_hashtable(TRSYMHTABSIZE);
if (buf = get_option_arg(argc,argv,&i)) {
struct SymNames **chain =
&gv->trace_syms[elf_hash(buf)%TRSYMHTABSIZE];
while (*chain)
chain = &(*chain)->next;
*chain = alloczero(sizeof(struct SymNames));
(*chain)->name = buf;
}
else
error(5,'y'); /* option requires argument */
break;
case 'B': /* set link mode */
if (buf = get_option_arg(argc,argv,&i)) {
if (!strcmp(buf,"static")) {
dynamic = FALSE;
}
else if (!strcmp(buf,"dynamic")) {
dynamic = TRUE;
}
else if (!strcmp(buf,"shareable")) {
gv->dest_object = TRUE;
gv->dest_sharedobj = TRUE;
}
else if (!strcmp(buf,"forcearchive")) {
gv->whole_archive = TRUE;
}
else if (!strcmp(buf,"symbolic")) {
; /* don't know, what this means... */
}
else {
error(3,buf); /* unknown link mode */
}
}
else
error(5,'B'); /* option requires argument */
break;
case 'F': /* read a file with object file names */
if (buf = get_option_arg(argc,argv,&i))
ReadListFile(gv,buf);
else
error(5,'F'); /* option requires argument */
break;
case 'L': /* new library search path */
if (buf = get_option_arg(argc,argv,&i)) {
libp = alloc(sizeof(struct LibPath));
libp->path = buf;
addtail(&gv->libpaths,&libp->n);
}
else
error(5,'L'); /* option requires argument */
break;
case 'M': /* mapping output */
gv->map_file = stdout;
break;
case 'R': /* use short form for relocations */
gv->short_rel = TRUE;
break;
case 'S': /* strip debugger symbols */
gv->strip_symbols = STRIP_DEBUG;
break;
case 'T': /* define base address of a section */
if (buf = get_option_arg(argc,argv,&i)) {
if (++i < argc) {
struct SecBase *sb = alloczero(sizeof(struct SecBase));
struct SecBase *p = (struct SecBase *)&gv->secbases;
sb->name = buf;
sscanf(argv[i],"%li",(long *)&sb->base); /* set base address */
while (p->next)
p = p->next;
p->next = sb;
}
}
error(5,'T'); /* option requires argument */
break;
case 'V': /* set minimum version for next shared object */
if (buf = get_option_arg(argc,argv,&i))
so_version = atoi(buf);
else
error(5,'V'); /* option requires argument */
break;
case 'X': /* discard temporary local symbols only */
gv->discard_local = DISLOC_TMP;
break;
default:
error(2,argv[i]); /* unrecognized option */
break;
}
}
else { /* normal input file name */
ifn = alloc(sizeof(struct InputFile));
ifn->name = argv[i];
ifn->lib = FALSE;
addtail(&gv->inputlist,&ifn->n);
}
}
if (listempty(&gv->inputlist))
error(6); /* no input files */
/* link them... */
linker_init(gv);
linker_load(gv); /* load all objects and libraries and their symbols */
linker_resolve(gv); /* resolve symbol references */
linker_relrefs(gv); /* find all relative references between sections */
linker_join(gv); /* join sections with same name and type */
linker_copy(gv); /* copy section contents and fix symbol offsets */
linker_relocate(gv); /* relocate addresses in joined sections */
linker_write(gv); /* write output file in selected target format */
linker_cleanup(gv);
cleanup(gv);
}
static char *get_option_arg(int argc,char *argv[],int *i)
/* get pointer to the string, which either directly follows the option
character or is stored in the next argument */
{
if (argv[*i][2])
return (&argv[*i][2]);
else {
if (++*i<argc) {
if (argv[*i][0]!='-' || isdigit(argv[*i][1])) /* another option? */
return (argv[*i]);
else
--*i;
}
}
return NULL;
}
static void ReadListFile(struct GlobalVars *gv,char *name)
/* read a file, which contains a list of object file names */
{
FILE *f;
struct InputFile *ifn;
char buf[256],c,*p,*n=NULL;
if (f = fopen(name,"r")) {
while (fgets(buf,255,f)) {
p = buf;
do {
c = *p++;
if (c=='\"') { /* read file name in quotes */
n = p;
while (*p && *p!='\"')
++p;
c = *p++ ? 1:0;
}
else if (c>' ' && !n)
n = p-1; /* new file name */
if (c<=' ' && n) { /* file name ends here */
*(p-1) = 0;
ifn = alloc(sizeof(struct InputFile));
ifn->name = allocstring(n);
ifn->lib = FALSE;
addtail(&gv->inputlist,&ifn->n);
n = NULL;
}
}
while (c);
}
fclose(f);
}
else
error(8,name); /* cannot open */
}
void cleanup(struct GlobalVars *gv)
{
exit(gv->returncode);
}